home *** CD-ROM | disk | FTP | other *** search
/ InterCD 2000 September / september_2000.iso / intercd / root / ^Linux / WindowMaker / wrlib / gradient.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-03-30  |  12.7 KB  |  488 lines

  1. /* gradient.c - renders gradients
  2.  *
  3.  *  Raster graphics library
  4.  *
  5.  *  Copyright (c) 1997-2000 Alfredo K. Kojima
  6.  *  Copyright (c) 1998-2000 Dan Pascu
  7.  *
  8.  *  This library is free software; you can redistribute it and/or
  9.  *  modify it under the terms of the GNU Library General Public
  10.  *  License as published by the Free Software Foundation; either
  11.  *  version 2 of the License, or (at your option) any later version.
  12.  *  
  13.  *  This library is distributed in the hope that it will be useful,
  14.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  15.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  16.  *  Library General Public License for more details.
  17.  *  
  18.  *  You should have received a copy of the GNU Library General Public
  19.  *  License along with this library; if not, write to the Free
  20.  *  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  21.  */
  22.  
  23. #include <config.h>
  24.  
  25. #include <stdlib.h>
  26. #include <stdio.h>
  27. #include <string.h>
  28.  
  29. #include <assert.h>
  30.  
  31. #include "wraster.h"
  32.  
  33.  
  34. static RImage *renderHGradient(unsigned width, unsigned height, 
  35.                    int r0, int g0, int b0, 
  36.                    int rf, int gf, int bf);
  37. static RImage *renderVGradient(unsigned width, unsigned height, 
  38.                    int r0, int g0, int b0, 
  39.                    int rf, int gf, int bf);
  40. static RImage *renderDGradient(unsigned width, unsigned height, 
  41.                    int r0, int g0, int b0, 
  42.                    int rf, int gf, int bf);
  43.  
  44. static RImage *renderMHGradient(unsigned width, unsigned height, 
  45.                 RColor **colors, int count);
  46. static RImage *renderMVGradient(unsigned width, unsigned height,
  47.                 RColor **colors, int count);
  48. static RImage *renderMDGradient(unsigned width, unsigned height, 
  49.                 RColor **colors, int count);
  50.  
  51. RImage*
  52. RRenderMultiGradient(unsigned width, unsigned height, RColor **colors, int style)
  53. {
  54.     int count;
  55.  
  56.     count = 0;
  57.     while (colors[count]!=NULL) count++;
  58.  
  59.     if (count > 2) {
  60.     switch (style) {
  61.      case RHorizontalGradient:
  62.         return renderMHGradient(width, height, colors, count);
  63.      case RVerticalGradient:
  64.         return renderMVGradient(width, height, colors, count);
  65.      case RDiagonalGradient:
  66.         return renderMDGradient(width, height, colors, count);
  67.     }
  68.     } else if (count > 1) {
  69.     return RRenderGradient(width, height, colors[0], colors[1], style);
  70.     } else if (count > 0) {
  71.     return RRenderGradient(width, height, colors[0], colors[0], style);
  72.     }
  73.     assert(0);
  74.     return NULL;
  75. }
  76.  
  77.  
  78.  
  79. RImage*
  80. RRenderGradient(unsigned width, unsigned height, RColor *from, RColor *to, 
  81.         int style)
  82. {
  83.     switch (style) {
  84.      case RHorizontalGradient:
  85.     return renderHGradient(width, height, from->red, from->green, 
  86.                    from->blue, to->red, to->green, to->blue);
  87.      case RVerticalGradient:
  88.     return renderVGradient(width, height, from->red, from->green, 
  89.                    from->blue, to->red, to->green, to->blue);
  90.  
  91.      case RDiagonalGradient:
  92.     return renderDGradient(width, height, from->red, from->green, 
  93.                    from->blue, to->red, to->green, to->blue);
  94.     }
  95.     assert(0);
  96.     return NULL;
  97. }
  98.  
  99.  
  100. /*
  101.  *----------------------------------------------------------------------
  102.  * renderHGradient--
  103.  *     Renders a horizontal linear gradient of the specified size in the
  104.  * RImage format with a border of the specified type. 
  105.  * 
  106.  * Returns:
  107.  *     A 24bit RImage with the gradient (no alpha channel).
  108.  * 
  109.  * Side effects:
  110.  *     None
  111.  *---------------------------------------------------------------------- 
  112.  */
  113. static RImage*
  114. renderHGradient(unsigned width, unsigned height, int r0, int g0, int b0, 
  115.         int rf, int gf, int bf)
  116. {    
  117.     int i;
  118.     unsigned long r, g, b, dr, dg, db;
  119.     RImage *image;
  120.     unsigned char *ptr;
  121.  
  122.     image = RCreateImage(width, height, False);
  123.     if (!image) {
  124.     return NULL;
  125.     }
  126.     ptr = image->data;
  127.  
  128.     r = r0 << 16;
  129.     g = g0 << 16;
  130.     b = b0 << 16;
  131.     
  132.     dr = ((rf-r0)<<16)/(int)width;
  133.     dg = ((gf-g0)<<16)/(int)width;
  134.     db = ((bf-b0)<<16)/(int)width;
  135.     /* render the first line */
  136.     for (i=0; i<width; i++) {
  137.     *(ptr++) = (unsigned char)(r>>16);
  138.     *(ptr++) = (unsigned char)(g>>16);
  139.     *(ptr++) = (unsigned char)(b>>16);
  140.     r += dr;
  141.     g += dg;
  142.     b += db;
  143.     }
  144.  
  145.     /* copy the first line to the other lines */
  146.     for (i=1; i<height; i++) {
  147.     memcpy(&(image->data[i*width*3]), image->data, width*3);
  148.     }
  149.     return image;
  150. }
  151.  
  152.  
  153.  
  154. /*
  155.  *----------------------------------------------------------------------
  156.  * renderVGradient--
  157.  *      Renders a vertical linear gradient of the specified size in the
  158.  * RImage format with a border of the specified type.
  159.  *
  160.  * Returns:
  161.  *      A 24bit RImage with the gradient (no alpha channel).
  162.  *
  163.  * Side effects:
  164.  *      None
  165.  *----------------------------------------------------------------------
  166.  */
  167. static RImage*
  168. renderVGradient(unsigned width, unsigned height, int r0, int g0, int b0,
  169.         int rf, int gf, int bf)
  170. {
  171.     int i, j;
  172.     unsigned long r, g, b, dr, dg, db;
  173.     RImage *image;
  174.     unsigned char *ptr;
  175.     unsigned char rr, gg, bb;
  176.  
  177.     image = RCreateImage(width, height, False);
  178.     if (!image) {
  179.     return NULL;
  180.     }    
  181.     ptr = image->data;
  182.  
  183.     r = r0<<16;
  184.     g = g0<<16;
  185.     b = b0<<16;
  186.  
  187.     dr = ((rf-r0)<<16)/(int)height;
  188.     dg = ((gf-g0)<<16)/(int)height;
  189.     db = ((bf-b0)<<16)/(int)height;
  190.  
  191.     for (i=0; i<height; i++) {
  192.     rr = r>>16;
  193.     gg = g>>16;
  194.     bb = b>>16;
  195.     for (j=0; j<width/8; j++) {
  196.         *(ptr++) = rr; *(ptr++) = gg; *(ptr++) = bb;
  197.         *(ptr++) = rr; *(ptr++) = gg; *(ptr++) = bb;
  198.         *(ptr++) = rr; *(ptr++) = gg; *(ptr++) = bb;
  199.         *(ptr++) = rr; *(ptr++) = gg; *(ptr++) = bb;
  200.         *(ptr++) = rr; *(ptr++) = gg; *(ptr++) = bb;
  201.         *(ptr++) = rr; *(ptr++) = gg; *(ptr++) = bb;
  202.         *(ptr++) = rr; *(ptr++) = gg; *(ptr++) = bb;
  203.         *(ptr++) = rr; *(ptr++) = gg; *(ptr++) = bb;
  204.     }
  205.     switch (width%8) {
  206.      case 7: *(ptr++) = rr; *(ptr++) = gg; *(ptr++) = bb;
  207.      case 6: *(ptr++) = rr; *(ptr++) = gg; *(ptr++) = bb;
  208.      case 5: *(ptr++) = rr; *(ptr++) = gg; *(ptr++) = bb;
  209.      case 4: *(ptr++) = rr; *(ptr++) = gg; *(ptr++) = bb;
  210.      case 3: *(ptr++) = rr; *(ptr++) = gg; *(ptr++) = bb;
  211.      case 2: *(ptr++) = rr; *(ptr++) = gg; *(ptr++) = bb;
  212.      case 1: *(ptr++) = rr; *(ptr++) = gg; *(ptr++) = bb;
  213.     }
  214.         r+=dr;
  215.         g+=dg;
  216.         b+=db;
  217.     }
  218.     return image;
  219. }
  220.  
  221.  
  222. /*
  223.  *----------------------------------------------------------------------
  224.  * renderDGradient--
  225.  *      Renders a diagonal linear gradient of the specified size in the
  226.  * RImage format with a border of the specified type.
  227.  *
  228.  * Returns:
  229.  *      A 24bit RImage with the gradient (no alpha channel).
  230.  *
  231.  * Side effects:
  232.  *      None
  233.  *----------------------------------------------------------------------
  234.  */
  235.  
  236.  
  237. static RImage*
  238. renderDGradient(unsigned width, unsigned height, int r0, int g0, int b0,
  239.         int rf, int gf, int bf)
  240. {
  241.     RImage *image, *tmp;
  242.     int j;
  243.     float a, offset;
  244.     char *ptr;
  245.  
  246.     if (width == 1)
  247.         return renderVGradient(width, height, r0, g0, b0, rf, gf, bf);
  248.     else if (height == 1)
  249.         return renderHGradient(width, height, r0, g0, b0, rf, gf, bf);
  250.  
  251.     image = RCreateImage(width, height, False);
  252.     if (!image) {
  253.         return NULL;
  254.     }
  255.  
  256.     tmp = renderHGradient(2*width-1, 1, r0, g0, b0, rf, gf, bf);
  257.     if (!tmp) {
  258.         RDestroyImage(image);
  259.         return NULL;
  260.     }
  261.  
  262.     ptr = tmp->data;
  263.  
  264.     a = ((float)(width - 1))/((float)(height - 1));
  265.     width = width * 3;
  266.  
  267.     /* copy the first line to the other lines with corresponding offset */
  268.     for (j=0, offset=0.0; j<width*height; j += width) {
  269.     memcpy(&(image->data[j]), &ptr[3*(int)offset], width);
  270.         offset += a;
  271.     }
  272.  
  273.     RDestroyImage(tmp);
  274.     return image;
  275. }
  276.  
  277.  
  278. static RImage*
  279. renderMHGradient(unsigned width, unsigned height, RColor **colors, int count)
  280. {
  281.     int i, j, k;
  282.     unsigned long r, g, b, dr, dg, db;
  283.     RImage *image;
  284.     unsigned char *ptr;
  285.     unsigned width2;
  286.     
  287.     
  288.     assert(count > 2);
  289.     
  290.     image = RCreateImage(width, height, False);
  291.     if (!image) {
  292.     return NULL;
  293.     }
  294.     ptr = image->data;
  295.     
  296.     if (count > width)
  297.     count = width;
  298.     
  299.     if (count > 1)
  300.         width2 = width/(count-1);
  301.     else
  302.         width2 = width;
  303.     
  304.     k = 0;
  305.  
  306.     r = colors[0]->red << 16;
  307.     g = colors[0]->green << 16;
  308.     b = colors[0]->blue << 16;
  309.  
  310.     /* render the first line */
  311.     for (i=1; i<count; i++) {
  312.     dr = ((int)(colors[i]->red   - colors[i-1]->red)  <<16)/(int)width2;
  313.     dg = ((int)(colors[i]->green - colors[i-1]->green)<<16)/(int)width2;
  314.     db = ((int)(colors[i]->blue  - colors[i-1]->blue) <<16)/(int)width2;
  315.     for (j=0; j<width2; j++) {
  316.         *ptr++ = (unsigned char)(r>>16);
  317.         *ptr++ = (unsigned char)(g>>16);
  318.         *ptr++ = (unsigned char)(b>>16);
  319.         r += dr;
  320.         g += dg;
  321.         b += db;
  322.         k++;
  323.     }
  324.     r = colors[i]->red << 16;
  325.     g = colors[i]->green << 16;
  326.     b = colors[i]->blue << 16;
  327.     }
  328.     for (j=k; j<width; j++) {
  329.     *ptr++ = (unsigned char)(r>>16);
  330.     *ptr++ = (unsigned char)(g>>16);
  331.     *ptr++ = (unsigned char)(b>>16);
  332.     }
  333.     
  334.     /* copy the first line to the other lines */
  335.     for (i=1; i<height; i++) {
  336.     memcpy(&(image->data[i*width*3]), image->data, width*3);
  337.     }
  338.     return image;
  339. }
  340.  
  341.  
  342.  
  343.  
  344. static RImage*
  345. renderMVGradient(unsigned width, unsigned height, RColor **colors, int count)
  346. {
  347.     int i, j, k;
  348.     unsigned long r, g, b, dr, dg, db;
  349.     RImage *image;
  350.     unsigned char *ptr, *tmp;
  351.     unsigned height2;
  352.     int x;
  353.     unsigned char rr, gg, bb;
  354.     
  355.  
  356.     assert(count > 2);
  357.     
  358.     image = RCreateImage(width, height, False);
  359.     if (!image) {
  360.     return NULL;
  361.     }
  362.     ptr = image->data;
  363.     
  364.     if (count > height)
  365.     count = height;
  366.     
  367.     if (count > 1)
  368.         height2 = height/(count-1);
  369.     else
  370.         height2 = height;
  371.     
  372.     k = 0;
  373.  
  374.     r = colors[0]->red << 16;
  375.     g = colors[0]->green << 16;
  376.     b = colors[0]->blue << 16;
  377.  
  378.     for (i=1; i<count; i++) {
  379.     dr = ((int)(colors[i]->red   - colors[i-1]->red)  <<16)/(int)height2;
  380.     dg = ((int)(colors[i]->green - colors[i-1]->green)<<16)/(int)height2;
  381.     db = ((int)(colors[i]->blue  - colors[i-1]->blue) <<16)/(int)height2;
  382.  
  383.     for (j=0; j<height2; j++) {
  384.         rr = r>>16;
  385.         gg = g>>16;
  386.         bb = b>>16;
  387.  
  388.         for (x=0; x<width/4; x++) {
  389.         *ptr++ = rr; *ptr++ = gg; *ptr++ = bb;
  390.         *ptr++ = rr; *ptr++ = gg; *ptr++ = bb;
  391.         *ptr++ = rr; *ptr++ = gg; *ptr++ = bb;
  392.         *ptr++ = rr; *ptr++ = gg; *ptr++ = bb;
  393.         }
  394.         switch (width%4) {
  395.          case 3: *ptr++ = rr; *ptr++ = gg; *ptr++ = bb;
  396.          case 2: *ptr++ = rr; *ptr++ = gg; *ptr++ = bb;
  397.          case 1: *ptr++ = rr; *ptr++ = gg; *ptr++ = bb;
  398.         }
  399.         r += dr;
  400.         g += dg;
  401.         b += db;
  402.         k++;
  403.     }
  404.     r = colors[i]->red << 16;
  405.     g = colors[i]->green << 16;
  406.     b = colors[i]->blue << 16;
  407.     }
  408.  
  409.     rr = r>>16;
  410.     gg = g>>16;
  411.     bb = b>>16;
  412.  
  413.     if (k<height) {
  414.         tmp = ptr;
  415.         for (x=0; x<width/4; x++) {
  416.             *ptr++ = rr; *ptr++ = gg; *ptr++ = bb;
  417.             *ptr++ = rr; *ptr++ = gg; *ptr++ = bb;
  418.             *ptr++ = rr; *ptr++ = gg; *ptr++ = bb;
  419.             *ptr++ = rr; *ptr++ = gg; *ptr++ = bb;
  420.         }
  421.         switch (width%4) {
  422.         case 3: *ptr++ = rr; *ptr++ = gg; *ptr++ = bb;
  423.         case 2: *ptr++ = rr; *ptr++ = gg; *ptr++ = bb;
  424.         case 1: *ptr++ = rr; *ptr++ = gg; *ptr++ = bb;
  425.         default: break;
  426.         }
  427.  
  428.         for (j=k+1; j<height; j++) {
  429.             memcpy(ptr, tmp, width*3);
  430.             ptr += width*3;
  431.         }
  432.     }
  433.     
  434.     return image;
  435. }
  436.  
  437.  
  438. static RImage*
  439. renderMDGradient(unsigned width, unsigned height, RColor **colors, int count)
  440. {
  441.     RImage *image, *tmp;
  442.     float a, offset;
  443.     int j;
  444.     unsigned char *ptr;
  445.  
  446.     assert(count > 2);
  447.  
  448.     if (width == 1)
  449.         return renderMVGradient(width, height, colors, count);
  450.     else if (height == 1)
  451.         return renderMHGradient(width, height, colors, count);
  452.  
  453.     image = RCreateImage(width, height, False);
  454.     if (!image) {
  455.         return NULL;
  456.     }
  457.  
  458.     if (count > width)
  459.         count = width;
  460.     if (count > height)
  461.         count = height;
  462.  
  463.     if (count > 2)
  464.     tmp = renderMHGradient(2*width-1, 1, colors, count);
  465.     else
  466.     tmp = renderHGradient(2*width-1, 1, colors[0]->red<<8, 
  467.                   colors[0]->green<<8, colors[0]->blue<<8,
  468.                   colors[1]->red<<8, colors[1]->green<<8,
  469.                   colors[1]->blue<<8);
  470.  
  471.     if (!tmp) {
  472.         RDestroyImage(image);
  473.         return NULL;
  474.     }
  475.     ptr = tmp->data;
  476.  
  477.     a = ((float)(width - 1))/((float)(height - 1));
  478.     width = width * 3;
  479.  
  480.     /* copy the first line to the other lines with corresponding offset */
  481.     for (j=0, offset=0; j<width*height; j += width) {
  482.     memcpy(&(image->data[j]), &ptr[3*(int)offset], width);
  483.         offset += a;
  484.     }
  485.     RDestroyImage(tmp);
  486.     return image;
  487. }
  488.